<?php

namespace App\Services;

use App\Common\Libs\ArrayHelper;
use App\Common\Libs\IdBuilder;
use App\Consts\GlobalCollectConst;
use App\Consts\GlobalConst;
use App\Consts\GlobalCounterConst;
use App\Consts\GlobalNoteConst;
use App\Events\Collect\CancelCollectEvent;
use App\Events\Collect\CreateCollectEvent;
use App\Exceptions\Error;
use App\Formats\CollectFormat;
use App\Models\Cache\Cache;
use App\Models\Cache\CacheKey;
use App\Models\UserCollect;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;

class CollectService extends BaseService
{
    private $_repository;

    public function __construct()
    {
        parent::__construct();
        $this->_repository = repository()->CollectRepository;
    }

    /**
     * 获取用户收藏列表
     * @param $searchParams
     * @return array
     */
    public function getUserCollectList($searchParams)
    {
        $dataProvider = $this->_repository->getUserCollectList($searchParams);
        $pagination = $this->getPagination();
        $collects = $dataProvider->get();

        $list = formats()->CollectFormat->formatCollectList($collects, $searchParams['current_user_id'], CollectFormat::HOME_COLLECT_LIST);

        return self::outputMoreList($dataProvider, $pagination, $list);
    }

    /**
     * 新增收藏
     * @param $loadData
     * @return bool|\Illuminate\Http\JsonResponse|array
     */
    public function addCollect($loadData)
    {
        // 已删除笔记不可收藏，私密笔记非本人不可收藏
        if ($loadData['target_type'] == GlobalConst::TARGET_TYPE_NOTE) {
            $note = repository()->NoteRepository->getNoteById($loadData['target_id']);
            if ((!$note || ($note && $note->is_deleted == GlobalConst::IS_DELETED) || ($note && $note->is_public == GlobalNoteConst::IS_NOT_PUBLIC)) && $loadData['user_id'] != $note->user_id) {
                return Error::handle(lang('Note is disable'));
            }
        }

        // 防止连点
        $alreadyCollect = $this->judgeCollectedFromCache($loadData['user_id'], $loadData['target_id'], $loadData['package_id']);
        if ($alreadyCollect) {
            return true;
        }

        DB::beginTransaction();
        try {
            $collect = $this->_repository->getCollectByUserIdAndTargetId($loadData['user_id'], $loadData['target_id']);

            // 移动收藏记录
            if ($collect && $collect->package_id != $loadData['package_id']) {
                // 修改收藏记录的<package_id>
                $collect = $this->_repository->editCollect($collect, [
                    'package_id' => $loadData['package_id'],
                    'updated_at' => time(),
                ]);

                // 旧收藏夹内容总数 -1
                $oldCollectPackage = repository()->PackageRepository->getCollectPackageById($collect->package_id);
                $total = $oldCollectPackage->total - 1;
                $total = $total < 0 ? 0 : $total;
                repository()->PackageRepository->updateCollectPackage($oldCollectPackage, ['total' => $total]);

                // 新收藏夹内容总数 +1
                $newCollectPackage = repository()->PackageRepository->getCollectPackageById($loadData['package_id']);
                repository()->PackageRepository->updateCollectPackage($newCollectPackage, [
                    'total' => $newCollectPackage->total + 1,
                    'updated_at' => time()
                ]);

                DB::commit();

                return ArrayHelper::toArray($collect);
            }

            if ($collect) {
                // 用户已经收藏，更新用户收藏缓存以防止重复收藏
                if ($collect->is_deleted == GlobalConst::IS_NOT_DELETE) {
                    $this->_flagCollected([
                        'user_id' => $collect->user_id,
                        'target_id' => $collect->target_id,
                        'package_id' => $collect->package_id,
                    ]);

                    return ArrayHelper::toArray($collect);
                }

                // 用户取消了收藏，更新记录
                $this->_repository->editCollect($collect, ['is_deleted' => GlobalConst::IS_NOT_DELETE]);
            } else {
                $loadData = ArrayHelper::merge($loadData, [
                    'collect_id' => IdBuilder::getUniqueID(),
                    'is_deleted' => GlobalConst::IS_NOT_DELETE,
                    'created_at' => time(),
                    'updated_at' => time(),
                ]);

                // 新增收藏
                $collect = $this->_repository->addCollect($loadData);
                if (!$collect) {
                    return Error::handle();
                }
            }

            // 如果[index_search_collect]存在记录，需要更新
            if ($collect->searchCollect) {
                $this->_repository->editSearchCollect($collect->searchCollect, [
                    'is_deleted' => GlobalConst::IS_NOT_DELETE
                ]);
            }

            // 同步更新主体计数、用户计数
            $this->_editCount($loadData['user_id'], $loadData['target_id'], $loadData['target_type']);

            // 更新用户收藏缓存以防止重复收藏
            $this->_flagCollected([
                'user_id' => $collect->user_id,
                'target_id' => $collect->target_id,
                'package_id' => $collect->package_id,
            ]);

            /**
             * 队列做以下几件事：
             *  1. 更新收藏夹总数 +1
             *  2. 记录日志
             *  3. 【暂时】新增[index_search_collect]记录
             */
            CreateCollectEvent::dispatch($collect);

            DB::commit();

            return ArrayHelper::toArray($collect);
        } catch (\Exception $e) {
            DB::rollBack();
            return Error::throw($e);
        }
    }

    /**
     * 取消收藏
     * @param $loadData
     * @return bool|\Illuminate\Http\JsonResponse
     */
    public function cancelCollect($loadData)
    {
        // 防止连点
        $alreadyCancelCollect = $this->judgeCollectedFromCache($loadData['user_id'], $loadData['target_id'], $loadData['package_id'], true);
        if ($alreadyCancelCollect) {
            return true;
        }

        DB::beginTransaction();
        try {
            // 用户已经取消收藏，更新用户收藏缓存以防止重复收藏
            $collect = $this->_repository->getCollectByUserIdAndTargetId($loadData['user_id'], $loadData['target_id']);
            if ($collect && $collect->is_deleted == GlobalConst::IS_DELETED) {
                $this->_flagCollected([
                    'user_id' => $collect->user_id,
                    'target_id' => $collect->target_id,
                    'package_id' => $collect->package_id,
                ], true);
                return true;
            }

            // 更新收藏记录
            $this->_repository->editCollect($collect, ['is_deleted' => GlobalConst::IS_DELETED]);

            // 同步更新主体计数、用户计数
            $this->_editCount($loadData['user_id'], $loadData['target_id'], $collect->target_type, GlobalCounterConst::DECREASE);

            // 更新用户收藏缓存以防止重复收藏
            $this->_flagCollected([
                'user_id' => $collect->user_id,
                'target_id' => $collect->target_id,
                'package_id' => $collect->package_id,
            ], true);

            /**
             * 队列做以下几件事：
             *  1. 更新收藏夹总数 -1
             *  2. 记录日志
             *  3. 删除[index_search_collect]
             */
            CancelCollectEvent::dispatch($collect);

            DB::commit();

            return true;
        } catch (\Exception $e) {
            DB::rollBack();
            return Error::throw($e);
        }
    }

    /**
     * 【暂时】新增[index_search_collect]记录
     * @param $loadData
     * @return UserCollect|\Illuminate\Database\Eloquent\Builder|null
     */
    public function addSearchCollect($loadData)
    {
        $searchTitle = '';
        if ($loadData['target_type'] == GlobalConst::TARGET_TYPE_ARTICLE) {
            $article = repository()->ArticleRepository->getArticleByArticleId($loadData['target_id']);
            if ($article) {
                $searchTitle = $article->title;
            }
        }

        if ($loadData['target_type'] == GlobalConst::TARGET_TYPE_ARTICLE) {
            $note = repository()->NoteRepository->getNoteByNoteId($loadData['target_id']);
            if ($note) {
                $searchTitle = $note->content;
            }
        }

        return $this->_repository->addSearchCollect([
            'collect_id' => IdBuilder::getUniqueID(),
            'search_title' => $searchTitle,
            'user_id' => $loadData['user_id'],
            'package_id' => $loadData['package_id']
        ]);
    }

    /**
     * 【暂时】删除[index_search_collect]记录
     * @param $collectId
     * @param $userId
     * @return bool|int
     */
    public function delSearchCollect($collectId, $userId)
    {
        return $this->_repository->delSearchCollect($collectId, $userId);
    }

    /**
     * 判断用户是否收藏某主体
     * @param $userId
     * @param $targetId
     * @return int
     */
    public function judgeCollected($userId, $targetId)
    {
        if (!$userId) {
            return GlobalCollectConst::USER_NOT_COLLECT;
        }
        $collect = $this->_repository->getCollectByUserIdAndTargetId($userId, $targetId);

        return $collect && $collect->is_deleted == GlobalConst::IS_NOT_DELETE ? GlobalCollectConst::USER_IS_COLLECTED : GlobalCollectConst::USER_NOT_COLLECT;
    }

    /**
     * 从缓存中验证用户对主体是否收藏过，或取消过收藏
     * @param $userId
     * @param $targetId
     * @param $packageId
     * @param false $isCancel
     * @return mixed
     */
    public function judgeCollectedFromCache($userId, $targetId, $packageId, $isCancel = false)
    {
        $keyParams = [
            'user_id' => $userId,
            'target_id' => $targetId,
            'package_id' => $packageId,
        ];
        if ($isCancel) {
            $cacheKey = CacheKey::CANCEL_COLLECT_USER_TARGET;
        } else {
            $cacheKey = CacheKey::COLLECT_USER_TARGET;
        }

        return Cache::getInstance($keyParams)->get($cacheKey);
    }

    /**
     * 找到用户对于某主体的正常收藏记录
     * @param $userId
     * @param $targetId
     * @return UserCollect|Builder|\Illuminate\Database\Eloquent\Model|object|null
     */
    public function getNormalCollectByTarget($userId, $targetId)
    {
        return $this->_repository->getNormalCollectByTarget($userId, $targetId);
    }

    /**
     * 获取收藏的主体的用户
     * @param $targetId
     * @param $targetType
     * @return bool|string
     */
    public function getTargetUserId($targetId, $targetType)
    {
        $receiveUserId = '';
        if ($targetType == GlobalConst::TARGET_TYPE_ARTICLE) {
            $article = repository()->ArticleRepository->getArticleByArticleId($targetId);
            if ($article) {
                $receiveUserId = $article['author_id'];
            }
        }

        if ($targetType == GlobalConst::TARGET_TYPE_NOTE) {
            $note = repository()->NoteRepository->getNoteByNoteId($targetId);
            if ($note) {
                $receiveUserId = $note['user_id'];
            }
        }

        return $receiveUserId ?? false;
    }

    /**
     * 更新用户收藏缓存以防止重复收藏
     *  1.收藏信息入缓存
     *  2.清除取消收藏信息缓存
     * @param array $keyParams
     * @param bool $isCancel
     * @return bool
     */
    private function _flagCollected($keyParams, $isCancel = false)
    {
        if ($isCancel) {
            Cache::getInstance($keyParams)->setnx(CacheKey::CANCEL_COLLECT_USER_TARGET, true);
            Cache::getInstance($keyParams)->delete(CacheKey::COLLECT_USER_TARGET);
            return true;
        }

        Cache::getInstance($keyParams)->setnx(CacheKey::COLLECT_USER_TARGET, true);
        Cache::getInstance($keyParams)->delete(CacheKey::CANCEL_COLLECT_USER_TARGET);

        return true;
    }

    /**
     * 同步用户基数、主体计数
     * @param string $userId
     * @param string $targetId
     * @param int $trend
     * @return bool
     */
    private function _editCount($userId, $targetId, $targetType, $trend = GlobalCounterConst::INCREASE)
    {
        service()->CounterService->editUserCount($userId, GlobalCounterConst::COUNT_COLLECT, $trend);

        service()->CounterService->editTargetCountByTargetType($targetId, $targetType, GlobalCounterConst::COUNT_COLLECT, $trend);

        return true;
    }
}
